/*
 * OPIAM Suite
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package opiam.admin.faare.persistence;

import opiam.admin.faare.MessageUtil;
import opiam.admin.faare.PropertiesManager;
import opiam.admin.faare.SearchResult;
import opiam.admin.faare.config.javabeans.JBClassDescriptor;
import opiam.admin.faare.config.javabeans.JBFieldDescriptor;
import opiam.admin.faare.config.javabeans.JBLdapConfig;
import opiam.admin.faare.config.javabeans.JBRessource;
import opiam.admin.faare.config.javabeans.JBSearchReferenceListDescriptor;
import opiam.admin.faare.exception.PersistenceException;
//DW/2620/BeginPatch
import opiam.admin.faare.persistence.javabeans.JBDynamicGroup;
//DW/2620/EndPatch
import opiam.admin.faare.persistence.javabeans.JBTop;
import opiam.admin.faare.persistence.javabeans.JBUser;
import opiam.admin.faare.service.UserContext;
import opiam.admin.faare.service.javabeans.SearchArgument;
import opiam.admin.faare.service.services.acl.AclsService;
import opiam.admin.faare.service.services.references.ReferenceElement;
import opiam.admin.faare.service.services.references.ReferenceList;
import opiam.admin.faare.utils.StringUtil;

import netscape.ldap.LDAPAttribute;
import netscape.ldap.LDAPAttributeSet;
import netscape.ldap.LDAPConnection;
import netscape.ldap.LDAPDN;
import netscape.ldap.LDAPEntry;
import netscape.ldap.LDAPException;
import netscape.ldap.LDAPModification;
import netscape.ldap.LDAPModificationSet;
import netscape.ldap.LDAPReferralException;
//DW/2662/BeginPatch
import netscape.ldap.util.DN;
//DW/2662/EndPatch

//DW/2584/BeginPatch
import netscape.ldap.LDAPSearchConstraints;

//DW/2584/EndPatch
import netscape.ldap.LDAPSearchResults;

//DW/2584/BeginPatch
import netscape.ldap.LDAPSortKey;

//DW/2584/EndPatch
import netscape.ldap.LDAPUrl;

//DW/2584/BeginPatch
import netscape.ldap.controls.LDAPSortControl;

//DW/2584/EndPatch
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;

import org.apache.log4j.Logger;

import java.lang.reflect.Constructor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;


/**
 * This class is the Persistence layer main class.
 */
public final class PersistenceLDAP
{
    /** Instance of logger. */
    private static Logger _logger = Logger.getLogger(PersistenceLDAP.class);

    /** Default selected attributes in search operations. */
    private static String[] _attrsSelected = {"*", "modifytimestamp"};

    /** Selected attributes in search operations, without modifytimestamp. */
    private static String[] _attrsWithoutModifyTimestamp = {"*"};

    /** Modifytimestamp as selected attributes in search operations. */
    private static String[] _attrsModifyTimestamp = {"modifytimestamp"};

    /** Object class attribute. */
    private static String _objectclassLdap = "objectclass";

    /** Dname field in mapped attributes. */
    private static String _dnLdap = "dn";

    /**
     * Utility class.
     */
    private PersistenceLDAP()
    {
    }

    /**
     * Checks whether the entry is in the resource given by the name and
     * in the current profile in the userContext.
     *
     * @param jbTop Entry to be checked.
     * @param resourceName Resource name.
     * @param userContext Current user context.
     *
     * @return true if it is, false if it is not.
     */
    public static boolean isJbTopInResource(JBTop jbTop, String resourceName,
        UserContext userContext)
    {
        JBRessource jbRessource = userContext.findJBRessourceByName(resourceName);

        if (jbRessource == null)
        {
            _logger.info(resourceName + " not found in isJbTopInResource");

            return false;
        }

        String filter = jbRessource.getLdapFilterParam();

        if (filter == null)
        {
            // pas de filtrage supplementaire, depend uniquement du type
            return (jbRessource.getType().equals(jbTop.getClass().getName()));
        }
        //DW/2674//BeginPatch
        if (!(jbRessource.getType().equals(jbTop.getClass().getName())))
        {
        	return false;
        }
        //DW/2674//EndPatch

        try
        {
            LDAPConnection ld = userContext.getLd();

            String[] attrs = {"dn"};
            String base = jbTop.getDn();
            LDAPSearchResults res = ld.search(base, LDAPConnection.SCOPE_BASE,
                    filter, attrs, false);

            //On parcourt les r�sultats
            if (res.hasMoreElements())
            {
                return true;
            }
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
        }

        return false;
    }

    /**
     * Gets search reference list, searching corresponding entries.
     *
     * @param desc Reference list decsriptor.
     *
     * @return Generated search reference list.
     * @throws PersistenceException if a LDAP error occurs.
     */
    public static ReferenceList getReferenceList(
        JBSearchReferenceListDescriptor desc) throws PersistenceException
    {
        ReferenceList result = new ReferenceList(desc);

        try
        {
            UserContext userContext = new UserContext();
            userContext.setLdapConfig(PropertiesManager.getInstance()
                                                       .getPersistenceDescriptionMap()
                                                       .getLdapConfig());

            LDAPConnection ld = LdapUtil.getAppliConnection(userContext);

            LDAPSearchResults res = ld.search(desc.getDn(),
                    LDAPConnection.SCOPE_SUB, desc.getFilter(),
                    desc.getAttributes(), false);

            //On parcourt les r�sultats
            Object o = null;
            LDAPAttribute ldapAttr = null;
            LDAPEntry entry = null;
            String label;
            String value;
            String attrType;

            while (res.hasMoreElements())
            {
                o = res.next();

                if (o instanceof LDAPEntry)
                {
                    entry = (LDAPEntry) o;

                    // traitement de LABEL
                    attrType = desc.getLabelattr();

                    if (attrType.compareToIgnoreCase("dn") == 0)
                    {
                        label = entry.getDN();
                    }
                    else
                    {
                        ldapAttr = entry.getAttribute(attrType);

                        if (ldapAttr == null)
                        {
                            _logger.info(
                                "error getReferenceList labelattr not exists");

                            continue;
                        }
                        else
                        {
                            label = ldapAttr.getStringValueArray()[0];
                        }
                    }

                    // traitement de VALUE
                    attrType = desc.getValueattr();

                    if (attrType.compareToIgnoreCase("dn") == 0)
                    {
                        value = entry.getDN();
                    }
                    else
                    {
                        ldapAttr = entry.getAttribute(attrType);

                        if (ldapAttr == null)
                        {
                            _logger.info(
                                "error getReferenceList Valueattr not exists");

                            continue;
                        }
                        else
                        {
                            value = ldapAttr.getStringValueArray()[0];
                        }
                    }

                    // creation de ref element
                    ReferenceElement elt = new ReferenceElement(label, value);
                    result.addReference(elt);
                }
            }

            if (desc.isToSort())
            {
                // trier par le label
                result.sortReference();
            }
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_LDAP_ERROR", LdapUtil.getLDAPErrorMessage(le)));
        }

        return result;
    }

    /**
     * Loads a JBTop object from its dname.
     *
     * @param dn Dname of the object.
     * @param userContext Current user context.
     * @return JBTop Loaded object
     * @throws PersistenceException if an error occurs.
     */
    public static JBTop load(String dn, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------LOAD1 BY DN DEBUT--------------");

        JBTop jbTop = load(dn, true, userContext);

        return jbTop;
    }

    //-- load

    /**
     * Loads a JBTop object from its dname.
     *
     * @param dn Dname of the object.
     * @param checkDateModify If true, load from directory only if modified since last loading.
     * @param userContext Current user context.
     * @return JBTop Loaded object
     * @throws PersistenceException if an error occurs.
     */
    public static JBTop load(String dn, boolean checkDateModify,
        UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------LOAD1 DEBUT--------------");

        if (dn == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        JBTop jbTop = null;

        try
        {
            Map hCache = userContext.getCache();
            LDAPConnection ld = userContext.getLd();

            if (hCache == null)
            {
                throw new PersistenceException(MessageUtil.formatMessage(
                        "MSG_VARIABLE_NULL", "hCache", "load", "PersistenceLDAP"));
            }

            //1er cas: on ne prend pas en compte la derni�re date de modification
            // de l'entr�e LDAP
            if (!checkDateModify)
            {
                if (getFromCache(dn, hCache) != null)
                {
                    //Un object avec le m�me DN se trouve dans le cache, on le retourne
                    jbTop = (JBTop) getFromCache(dn, hCache);
                }
                else
                {
                    //Object non trouv� dans le cache, on le charge
                    jbTop = internalLoad(ld, dn, userContext);

                    //Ajout de l'objet dans le cache
                    addToCache(jbTop, hCache, userContext);
                }
            }
            else
            {
                LDAPEntry entry = ld.read(dn, _attrsSelected);

                jbTop = (JBTop) getFromCache(dn, hCache);

                //Cas1: objet est dans le cache et date de modification inchang�e, on renvoie
                //      l'objet du cache
                if ((jbTop != null) &&
                    //DW/2577//BeginPatch
                    (jbTop.getModify() != null) &&
                    //DW/2577//EndPatch
                    jbTop.getModify().equals(LdapUtil.getModifyFromLDAPEntry(
                                entry)))
                {
                    _logger.debug(
                        "LOAD1 objet dans cache et date non modifiee avec le dn  : " +
                        dn);
                }
                else
                {
                    jbTop = internalLoad(ld, entry, null, userContext);
                    addToCache(jbTop, hCache, userContext);
                }
            }
        }
        catch (LDAPException le)
        {
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);
        }

        return jbTop;
    }

    //-- load

    /**
     * Gets a list of objects from their dname.
     * @param lDn List of dnames.
     * @param userContext Current user context.
     * @return List of loaded objects.
     * @throws PersistenceException If an error occurs.
     */
    public static List load(List lDn, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------LOAD4 DEBUT--------------");

        List result = new ArrayList();
        Iterator it = lDn.iterator();
        String dn = null;
        JBTop jbTop = null;

        while (it.hasNext())
        {
            dn = (String) it.next();
            jbTop = load(dn, userContext);
            result.add(jbTop);
        }

        return result;
    }

    /**
     * Gets an attribute values from the entry dname and the attribute name.
     *
     * @param dn Entry dname.
     * @param att Attribute name.
     * @param userContext Current user context,
     *                    or null to use applicative connection.
     * @param isBin true for binary attribute, false for strign attribute.
     * @return List of values.
     * @throws PersistenceException In case of null argument or LDAP error.
     */
    public static List loadAttribute(String dn, String att,
        UserContext userContext, boolean isBin) throws PersistenceException
    {
        _logger.debug(
            "-----------LOADATTRIBUTE UserContext DEBUT--------------");
        _logger.debug("LOADATTRIBUTE UserContext dn : " + dn);
        _logger.debug("LOADATTRIBUTE UserContext att : " + att);

        if (dn == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (att == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

/*
        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }
*/

        List returnedList = new ArrayList();

        try
        {
            LDAPConnection ld;
            if (userContext == null)
            {
                UserContext auserContext = new UserContext();
                auserContext.setLdapConfig(PropertiesManager.getInstance()
                                                       .getPersistenceDescriptionMap()
                                                       .getLdapConfig());

                ld = LdapUtil.getAppliConnection(auserContext);
            }
            else
            {
                ld = userContext.getLd();
            }
            String[] attrs = {att};

            LDAPEntry entry = ld.read(dn, attrs);
            _logger.debug("LOADATTRIBUTE UserContext entry : " + entry);

            LDAPAttribute ldapAtt = entry.getAttribute(att);
            _logger.debug("LOADATTRIBUTE UserContext ldapAtt : " + ldapAtt);

            if (ldapAtt != null)
            {
                // remplir returnedList avec les valeurs d'attributs
                if (isBin)
                {
                    returnedList.add(ldapAtt.getByteValues().nextElement());
                }
                else
                {
                    CollectionUtils.addAll(returnedList, ldapAtt.getStringValues());
                }
            }
        }
        catch (LDAPException le)
        {
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);
        }

        _logger.debug("LOADATTRIBUTE returnedList.size() : " +
            returnedList.size());

        return returnedList;
    }

    /**
     * Gets an attribute values from the entry dname and the attribute name.
     * Uses the applicative connection.
     * This method is useable for string attributes.
     *
     * @param dn Entry dname.
     * @param att Attribute name.
     * @return List of values.
     * @throws PersistenceException In case of null argument or LDAP error.
     */
    public static List loadAttribute(String dn, String att)
        throws PersistenceException
    {
        return loadAttribute(dn, att, null, false);
    }

    /**
     * Gets an attribute values from the entry dname and the attribute name.
     * This method is useable for string attributes.
     *
     * @param dn Entry dname.
     * @param att Attribute name.
     * @param userContext Current user context,
     *                    or null to use applicative connection.
     * @return List of values.
     * @throws PersistenceException In case of null argument or LDAP error.
     */
    public static List loadAttribute(String dn, String att,
        UserContext userContext) throws PersistenceException
    {
       return loadAttribute(dn, att, userContext, false);
    }

    /**
     * Gets an attribute values from the entry dname and the attribute name.
     * Uses the current user connection.
     * This method is useable for binary attributes.
     *
     * @param dn Entry dname.
     * @param att Attribute name.
     * @param userContext Current user context.
     * @return List of values.
     * @throws PersistenceException In case of null argument or LDAP error.
     */
    public static List loadBinaryAttribute(String dn, String att,
        UserContext userContext) throws PersistenceException
    {
        return loadAttribute(dn, att, userContext, true);
    }

    //-- loadAttribute

    /**
     * Modifies an entry from a modified business bean object.
     *
     * @param jbTop Modified business bean object.
     * @param userContext Current user context.
     * @return true
     * @throws PersistenceException in case of null argument or from internalModify() or from load()
     */
    public static boolean modify(JBTop jbTop, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------MODIFY1 DEBUT--------------");

        if (jbTop == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "jbTop", "modify", "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "modify",
                    "PersistenceLDAP"));
        }

        if (userContext.getJbUser() != null)
        {
            _logger.info(MessageUtil.formatMessage("MSG_MODIFY_ENTRY",
                    jbTop.getDn(), userContext.getJbUser().toString()));
        }

        boolean success = true;

        LDAPConnection ld = userContext.getLd();

        //Lancement du decompute avant la modification
        //Permet d'impl�menter les attributs calcul�s
        jbTop.decompute();

        //on regarde d'abord si le JBTop envoy� a �t� clon�
        Map hCache = userContext.getCache();

        //DW/2592/BeginPatch
        try
        {
            //DW/2592/EndPatch
            //1er Cas: dans le cache on a un objet avec le m�me Dn qui est diff�rent
            //         l'objet envoy� � modifier: il a donc �t� clon�
            if ((getFromCache(jbTop.getDn(), hCache) != null) &&
                    (getFromCache(jbTop.getDn(), hCache) != jbTop))
            {
//DW/2633/BeginPatch
                //transferFromClone((JBTop) getFromCache(jbTop.getDn(), hCache), jbTop);
                _logger.debug("modify with clone");
                internalModify(ld, jbTop, (JBTop) getFromCache(jbTop.getDn(), hCache),
                    userContext);
//DW/2633/EndPatch
                //2�me cas : l'objet n'a pas �t� clon�
            }
            else
            {
//DW/2633/BeginPatch
                _logger.debug("modify with LDAP entry");
                internalModify(ld, jbTop, (JBTop) null, userContext);
//DW/2633/EndPatch
            }

            //DW/2592/BeginPatch
        }
        catch (PersistenceException ex)
        {
            // reload entry from directory to cancel modification of object
            userContext.getCache().remove(userContext.getDn());
            jbTop = load(jbTop.getDn(), userContext);
            throw ex;
        }

        //DW/2592/EndPatch
        jbTop = load(jbTop.getDn(), userContext);

        return success;
    }

    /**
     * Modifies an attribute in a list of object.
     *
     * @param jbTopList List of objects to modify.
     * @param attribute Attribute to modify (business bean attribute name).
     * @param userContext Current user context.
     * @return true
     * @throws PersistenceException in case of null argument
     */
    public static boolean modify(List jbTopList, String attribute,
        UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------MODIFY3 LIST DEBUT ----------");

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (attribute == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        boolean success = true;

        try
        {
            LDAPConnection ld = userContext.getLd();

            JBTop jbTop = null;

            for (int i = 0; i < jbTopList.size(); i++)
            {
                //_logger.debug("-----------MODIFY jbTop : " + jbTopList.get(i).hashCode());
                jbTop = (JBTop) jbTopList.get(i);

                //Lancement du decompute avant la modification
                //Permet d'impl�menter les attributs calcul�s
                jbTop.decompute();

                if (userContext.getJbUser() != null)
                {
                    _logger.info(MessageUtil.formatMessage(
                            "MSG_MODIFY_ENTRY_ATT", attribute, jbTop.getDn(),
                            userContext.getJbUser().toString()));
                }

                Map hCache = userContext.getCache();

                if ((getFromCache(jbTop.getDn(), hCache) != null) &&
                        (getFromCache(jbTop.getDn(), hCache) != jbTop))
                {
                    _logger.debug("MODIFY objet a modifier a ete clone");
                    transferFromClone((JBTop) getFromCache(jbTop.getDn(), hCache),
                        jbTop);
                    internalModify(ld,
                        (JBTop) getFromCache(jbTop.getDn(), hCache), attribute,
                        userContext);
                }
                else
                {
                    _logger.debug("MODIFY LISTE objet a modifier non clone");
                    internalModify(ld, jbTop, attribute, userContext);
                }
            }
        }
        //DW/2640/BeginPatch
        catch (PersistenceException ex)
        {
            throw ex;
        }
        /*
        catch (Exception e)
        {
            e.printStackTrace();
        }
        */
        //DW/2640/EndPatch

        _logger.debug("-----------MODIFY3 FIN OK ----------");

        return success;
    }

    /**
     * Modifies given LDAP attribute with given value in given entry.
     * This method should be used when an LDAP attribute may be written
     * but not read (such as userpassword in some directories).
     *
     * @param dn Entry dname.
     * @param value Attribute value.
     * @param attribute Attribute LDAP name.
     * @param userContext Current user context.
     *
     * @return true
     *
     * @throws PersistenceException in case of null argument or LDAP error
     */
    public static boolean modifyLDAPHiddenAttribute(String dn, String value,
        String attribute, UserContext userContext) throws PersistenceException
    {
        _logger.debug(
            "-----------modifyLDAPHiddenAttribute LIST DEBUT ----------");

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (attribute == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        boolean success = true;

        try
        {
            LDAPConnection ld = userContext.getLd();

            LDAPModificationSet ldapModificationSet = new LDAPModificationSet();

            LDAPAttribute ldapAttr = new LDAPAttribute(attribute, value);

            if (value == null)
            {
                ldapModificationSet.add(LDAPModification.DELETE, ldapAttr);
            }
            else
            {
                ldapModificationSet.add(LDAPModification.REPLACE, ldapAttr);
            }

            ld.modify(dn, ldapModificationSet);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        _logger.debug("-----------MODIFY3 FIN OK ----------");

        return success;
    }

    //-- modify
    /**
     * Gets set of LDAP attributes from a business bean object.
     *
     * @param jbTop business bean object.
     * @return set of filled LDAP attributes.
     */
    public static LDAPAttributeSet getLdapAttributeSetFromJBTop(JBTop jbTop)
    {
        LDAPAttributeSet ldapAttributeSet = null;

        try
        {
            //Liste de LDAPAttribute
            List lAtt = new ArrayList();

            //Classe du JBTop � cr�er
            Class cl = jbTop.getClass();

            //R�cup�ration du JBClassDescriptor
            JBClassDescriptor classDesc = PropertiesManager.getInstance()
                                                           .getPersistenceDescriptionMap()
                                                           .getClassDescriptor(cl.getName());

            LDAPAttribute ldapAttr = null;
            JBFieldDescriptor fieldDesc = null;
            Iterator it = classDesc.getFields().iterator();

            // Parcours des attributs objets et cr�ation des LDAPAttribute correspondants
            while (it.hasNext())
            {
                fieldDesc = (JBFieldDescriptor) it.next();

                if (fieldDesc.getSrcDesc().getName().compareToIgnoreCase(_dnLdap) == 0)
                {
                    // ne pas traiter l'attribut "DN" (ce n'est pas un atttribut)
                    continue;
                }

                if (fieldDesc.getSrcDesc().getName().compareToIgnoreCase(_objectclassLdap) == 0)
                {
                    _logger.debug("CREATE objectclass trouv�");

                    List ocList = (List) LdapUtil.getFieldValue(fieldDesc, jbTop);

                    //Si l'attribut "objectclass" n'est pas renseign�, on le renseigne
                    //avec la valeur figurant dans le mapping
                    if ((ocList == null) || (ocList.size() == 0))
                    {
                        _logger.debug(
                            "CREATE objectclass nul donc on va le charger");
                        ldapAttr = LdapUtil.getObjectclassAttribute(jbTop.getClass()
                                                                         .getName());
                    }
                    else
                    {
                        ldapAttr = LdapUtil.getLDAPAttrFromFieldDesc(fieldDesc,
                                jbTop);
                    }
                }
                else
                {
                    ldapAttr = LdapUtil.getLDAPAttrFromFieldDesc(fieldDesc,
                            jbTop);
                }

                if (ldapAttr != null)
                {
                    lAtt.add(ldapAttr);
                }
            }

            //Transformation de la liste en tableau
            LDAPAttribute[] ldapTab = new LDAPAttribute[lAtt.size()];

            for (int i = 0; i < lAtt.size(); i++)
            {
                ldapTab[i] = (LDAPAttribute) lAtt.get(i);
            }

            ldapAttributeSet = new LDAPAttributeSet(ldapTab);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return ldapAttributeSet;
    }

    /**
     * Creates an entry from a business bean object.
     *
     * @param jbTop Business bean object.
     * @param userContext Current user context.
     *
     * @throws PersistenceException in case of null argument or LDAP error
     */
    public static void create(JBTop jbTop, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------CREATE DEBUT--------------");

        if (jbTop == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        try
        {
            LDAPConnection ld = userContext.getLd();

            LDAPAttributeSet ldapAttributeSet = getLdapAttributeSetFromJBTop(jbTop);

            _logger.debug("CREATE jbTop.getDn() : " + jbTop.getDn());
            ld.add(new LDAPEntry(jbTop.getDn(), ldapAttributeSet));

            //DW/2540/BeginPatch
            // on ne met pas l'objet dans le cache, puisqu'on n'a pas la date de modification
            // et que sans date de modification le LOAD1 cause une exception. On considere que
            // recharger une seule entree ne va pas penaliser trop. De plus cela permet de
            // beneficier des attributs calcules par l'annuaire.
            //DW/2540/EndPatch
        }
        catch (LDAPException le)
        {
            le.printStackTrace();

            /*DW/2547*/
            /*BeginPatch*/
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);

            /*DW/2547*/
            /*EndPatch*/
        }
    }

    //-- create

    /**
     * Deletes an entry corresponding to a business bean object.
     *
     * @param jbTop Business bean object.
     * @param userContext Current user context
     * @throws PersistenceException in case of null argument or LDAP error.
     */
    public static void delete(JBTop jbTop, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------DELETE DEBUT--------------");

        if (jbTop == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        try
        {
            LDAPConnection ld = userContext.getLd();
            ld.delete(jbTop.getDn());

            //on supprime du cache
            userContext.getCache().remove(jbTop.getDn());
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));

            /*DW/2547*/
            /*BeginPatch*/
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);

            /*DW/2547*/
            /*EndPatch*/
        }
    }

    /**
     * Searches entries from LDAP parameters.
     * Retrieves only entry dnames.
     *
     * @param filter LDAP search filter.
     * @param base LDAP search base, or null for application configured search base.
     * @param scope LDAP scope or null for subtree.
     * @param userContext Current user context
     *
     * @return SearchResult object containing list of dnames.
     *
     * @throws PersistenceException in case of null argument or LDAP error.
     */
    public static SearchResult searchDns(String filter, String base,
        Integer scope, UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------searchDns DEBUT--------------");

        if (filter == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        List results = new ArrayList();
        SearchResult searchResult = new SearchResult();
        searchResult.setSizeLimit(false);

        try
        {
            LDAPConnection ld = userContext.getLd();

            if ((base == null) || base.equalsIgnoreCase(""))
            {
                base = userContext.getLdapConfig().getBaseDN();
            }

            if (scope == null)
            {
                scope = new Integer(LDAPConnection.SCOPE_SUB);
            }

            String[] attributes = {"objectclass"};

            LDAPSearchResults res = ld.search(base, scope.intValue(), filter,
                    attributes, false);

            LDAPEntry entry = null;
            JBTop jbTop = null;
            Object o = null;

            //On parcourt les r�sultats
            try
            {
                while (res.hasMoreElements())
                {
                    o = res.next();

                    if (o != null)
                    {
                        if (o instanceof LDAPEntry)
                        {
                            results.add(LdapUtil.formatDN(
                                    ((LDAPEntry) o).getDN()));
                        }
                        else
                        {
                            searchResult.setSizeLimit(true);
                        }
                    }
                }
            }
            catch (LDAPException le)
            {
                searchResult.setSizeLimit(true);
            }
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
        }

        searchResult.setLResults(results);

        return searchResult;
    }

    /**
     * One level scope searches entries corrsponding to a search argument.
     *
     * @param arguments Search arguments (SearchArgument)
     * @param baseDn Base dname
     * @param userContext Current user context
     *
     * @return SearchResult object containing entries
     *
     * @throws PersistenceException in case of null argument or from internalSearch().
     */
    public static SearchResult searchOneLevel(List arguments, String baseDn,
        UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------SEARCHONELEVEL DEBUT (LISTE)--------------");

        if (arguments == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (baseDn == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        SearchResult result = new SearchResult();
        SearchResult result2 = new SearchResult();

        try
        {
            LDAPConnection ld = userContext.getLd();

            SearchResult partialResult = null;

            Iterator it = arguments.iterator();
            SearchArgument arg = null;

            while (it.hasNext())
            {
                arg = (SearchArgument) it.next();
                _logger.debug("searchOneLevel arg.getLdapFilter() : " +
                    arg.getLdapFilter());
                partialResult = internalSearch(ld, LDAPConnection.SCOPE_ONE,
                        arg.getLdapFilter(), arg.getLdapSearchAttributes(),
                        baseDn, arg.getJbRessource().getClassDesc(), userContext);

                result.addAll(partialResult);
            }

            //Ajout CCT 11/06/03 v�rification ACL
            List temp = result.getLResults();

            _logger.debug("searchOneLevel temp  : " + temp.size());

            List acls = new ArrayList();

            JBTop jbTop = null;

            for (int i = 0; i < temp.size(); i++)
            {
                jbTop = (JBTop) temp.get(i);

                if (AclsService.isVisualisationEnabled(jbTop, userContext))
                {
                    acls.add(jbTop);
                }
            }

            _logger.debug("searchOneLevel acls : " + acls.size());

            result2.setLResults(acls);
            result2.setSizeLimit(result.isSizeLimit());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return result2;
    }

    /**
     * Performs a search. Corresponds to StandardService.search().
     *
     * @param arguments Search arguments (list of SearchArgument).
     * @param userContext Current user context.
     *
     * @return SearchResult containing entries
     *
     * @throws PersistenceException from search(List,UserContext,String[]).
     */
    public static SearchResult search(List arguments, UserContext userContext)
        throws PersistenceException//DW/2584/BeginPatch
    {
        return search(arguments, userContext, null);
    }

    //DW/2595 : sortField devient un tableau
    /**
     * Performs a search. Corresponds to StandardService.search().
     *
     * @param arguments Search arguments (list of SearchArgument).
     * @param userContext Current user context.
     * @param sortFields Fields on which result must be sorted.
     *
     * @return SearchResult containing entries
     *
     * @throws PersistenceException in case of null argument or
     *             from search(SearchArgument,UserContext,String[]).
     */
    public static SearchResult search(List arguments, UserContext userContext,
        String[] sortFields) throws PersistenceException//DW/2584/EndPatch
    {
        _logger.debug("-----------SEARCH DEBUT (LIST)--------------");

        if (arguments == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        SearchResult result = new SearchResult();
        SearchResult partialResult = null;

        try
        {
            Iterator it = arguments.iterator();
            SearchArgument arg = null;

            while (it.hasNext())
            {
                arg = (SearchArgument) it.next();

                //DW/2584/BeginPatch
                //partialResult = search(arg, userContext);
                partialResult = search(arg, userContext, sortFields);

                //DW/2584/EndPatch
                result.addAll(partialResult);

                //DW/2552/Beginpatch
                if (!result.isSizeLimit())
                {
                    result.setSizeLimit(partialResult.isSizeLimit());
                }

                //DW/2552/Endpatch
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * Performs a search with one search argument.
     *
     * @param arg Search argument.
     * @param userContext Current user context.
     *
     * @return SearchResult containing entries.
     *
     * @throws PersistenceException from search (SearchArgument,UserContext,String[]).
     */
    public static SearchResult search(SearchArgument arg,
        UserContext userContext) throws PersistenceException//DW/2584/BeginPatch
    {
        return search(arg, userContext, null);
    }

    //DW/2595 : sortField devient un tableau
    /**
     * Performs a search with one search argument.
     *
     * @param arg Search arguments (list of SearchArgument).
     * @param userContext Current user context.
     * @param sortFields Fields on which result must be sorted.
     *
     * @return SearchResult containing entries
     *
     * @throws PersistenceException in case of null argument or
     *             from internalSearch().
     */
    public static SearchResult search(SearchArgument arg,
        UserContext userContext, String[] sortFields)
        throws PersistenceException//DW/2584/EndPatch
    {
        _logger.debug("-----------SEARCH DEBUT (SEARCHARGUMENT)--------------");

        if (arg == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        SearchResult result = new SearchResult();

        try
        {
            LDAPConnection ld = userContext.getLd();

            _logger.debug(" search arg.getCriteria() = " + arg.getCriteria());

            String ldapFilter = arg.getLdapFilter();

            _logger.debug(" search filter = " + ldapFilter);

            _logger.debug(" search arg.getJbRessource().getName() = " +
                arg.getJbRessource().getName());
            result =
                //DW/2584/BeginPatch
                internalSearch(ld, arg.getLdapScope(), ldapFilter,
                    arg.getLdapSearchAttributes(), arg.getLdapBase(),
                    arg.getJbRessource().getClassDesc(), userContext, sortFields);

            //DW/2584/EndPatch
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * Performs a login.
     *
     * @param login User login.
     * @param pwd User password.
     * @param ldapConfig LDAP server configuration.
     * @param userContext Context of user being logged in.
     *
     * @return true if login succeeded, false if it failed.
     *
     * @throws PersistenceException if "logon" resource is not defined,
     * or if an LDAP error occurred.
     */
    public static boolean logon(String login, String pwd,
        JBLdapConfig ldapConfig, UserContext userContext)
        throws PersistenceException
    {
        LDAPConnection adminLd = null;
        boolean isLoggedOn = false;

        try
        {
            if (ldapConfig == null)
            {
                ldapConfig = PropertiesManager.getInstance()
                                              .getPersistenceDescriptionMap()
                                              .getLdapConfig();
            }

            userContext.setLdapConfig(ldapConfig);

            _logger.debug("logon getBaseDN:  " + ldapConfig.getBaseDN());
            _logger.debug("logon getAppliDN:  " + ldapConfig.getAppliDN());
            _logger.debug("logon getAppliPwd:  " + ldapConfig.getAppliPwd());
            _logger.debug("logon getConnectionType:  " +
                ldapConfig.getConnectionType());
            _logger.debug("logon getHost:  " + ldapConfig.getHost());
            _logger.debug("logon getLdapPort:  " + ldapConfig.getLdapPort());

            // G�n�rer le filtre LDAP � partir de resource login
            JBRessource logonResource = PropertiesManager.getInstance()
                                                         .getJbProfiles()
                                                         .findRessourceByName("logon");

            if (logonResource == null)
            {
                _logger.debug("logon logonResource = null ");
                throw new PersistenceException(
                    "Global resource 'logon' not defined in profiles.xml");
            }

            StringBuffer filter = new StringBuffer();
            filter.append("(&(");
            filter.append(logonResource.getLoginAttributeParam());
            filter.append("=");
            filter.append(login);
            filter.append(")");
            filter.append(LdapObjectFilter.getLdapFilterFromResource(
                    logonResource, userContext));
            filter.append(")");
            _logger.debug("logon filter = " + filter.toString());

            // rechercher
            // se connecter en tant que Admin
            adminLd = LdapUtil.getAppliConnection(userContext);

            userContext.setAppliConnection(adminLd);

            SearchResult logonSearchResult = internalSearch(adminLd, LDAPConnection.SCOPE_SUB,
                    filter.toString(), null, null, null, userContext);

            _logger.debug("logon logonSearchResult.size() : " +
                logonSearchResult.getLResults().size());

            if (!logonSearchResult.getLResults().isEmpty())
            {
                //R�cup�ration du JBTop, prendre le premier sur la liste
                JBTop jbTop = (JBTop) logonSearchResult.getLResults().get(0);
                _logger.debug("logon jbTop.getDn() : " + jbTop.getDn());
                userContext.setJbUser((JBUser) jbTop);
                userContext.setDn(jbTop.getDn());

                LDAPConnection userLd = userContext.getLd();

                if (userLd == null)
                {
                    _logger.debug("logon userLd null ");
                    userLd = LdapUtil.getUnboundConnection(userContext);
                    userContext.setLd(userLd);
                }

                _logger.debug("logon ldapConfig.isAppliConnectionType() : " +
                    ldapConfig.isAppliConnectionType());

                _logger.debug("logon dn : " + userContext.getDn());

                _logger.debug("logon pwd : " + userContext.getPwd());

                userLd.bind(userContext.getDn(), userContext.getPwd());

                // check if should use userLd or adminLd
                if (ldapConfig.isAppliConnectionType())
                {
                    userLd.bind(ldapConfig.getAppliDN(),
                        ldapConfig.getAppliPwd());
                }

                //DW/2585/BeginPatch
                else
                /*
                 * search again entry using user connection because user may not see the same
                 * attributes as admin does.
                 */
                {
                    _logger.debug("logon reload " + userContext.getDn());

                    // remove from cache
                    userContext.getCache().remove(userContext.getDn());

                    // search again using user connection
                    SearchResult logonSearchResult2 = internalSearch(userLd, LDAPConnection.SCOPE_SUB,
                            "objectclass=*", null, userContext.getDn(), null,
                            userContext);

                    // update JBUser in user context
                    if (logonSearchResult2.getLResults().isEmpty())
                    {
                        userContext.setJbUser(null); // user can not see his own entry.
                    }
                    else
                    {
                        userContext.setJbUser((JBUser) logonSearchResult2.getLResults()
                                                                         .get(0));
                    }
                }

                //DW/2585/EndPatch
                isLoggedOn = true;
            }
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
//DW/2604/BeginPatch
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);
//DW/2604/EndPatch
        }

        return isLoggedOn;
    }

    /**
     * Checks whether given dname matches given filter.
     *
     * @param userDn Dname to be checked.
     * @param filter Filter to check.
     * @param userContext Current user context.
     *
     * @return true if it matches, fasle if it does not.
     *
     * @throws PersistenceException in case of null argument or LDAP error.
     */
    public static boolean isInFilterGroupAdmin(String userDn, String filter,
        UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------isInFilterGroupAdmin--------------");

        if (userDn == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        boolean find = false;
        LDAPConnection appliLd = null;

        try
        {
            // se connecter en tant que l'application
            appliLd = userContext.getAppliConnection();

            String[] attrs = {"objectclass"};

            LDAPSearchResults res = appliLd.search(userDn,
                    LDAPConnection.SCOPE_BASE, filter, attrs, true);

            //On parcourt les r�sultats
            if (res.hasMoreElements())
            {
                return true;
            }
        }
        catch (RuntimeException le)
        {
            throw new PersistenceException("run time exception", le);
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
        }

        return find;
    }

    /**
     * Gets groups the user with given dname belongs to.
     * Processes recursively static and dynamic groups.
     *
     * @param dn Dname to search for.
     * @param baseDN LDAP search base dname or null for application configured base dname.
     * @param jbStaticName static group resource name
     * @param jbDynamicName dynamic group resource name
     * @param uniquememberName static group membership attribute name.
     * @param memberUrlName dynamic group URL attribute name, or null if dynamic
     *        groups are not used.
     * @param userContext Current user context.
     *
     * @return List of group dnames the user belongs to.
     */
    public static Vector getGroupsAdmin(String dn, String baseDN,
        String jbStaticName, String jbDynamicName, String uniquememberName,
        String memberUrlName, UserContext userContext)
    {
        _logger.debug("getGroupsAdmin dn : " + dn);

        Vector v = new Vector();

        try
        {
            LDAPConnection appliLd = userContext.getAppliConnection();

            if (baseDN == null)
            {
                baseDN = userContext.getLdapConfig().getBaseDN();
            }

            _logger.debug("getGroupsAdmin baseDN : " + baseDN);

            if (jbStaticName == null)
            {
                jbStaticName = "opiam.admin.faare.persistence.javabeans.JBStaticGroup";
            }

            _logger.debug("getGroupsAdmin jbStaticName : " + jbStaticName);

            String uniquemberLdapAtt = LdapUtil.convertJBAttrNameToLdapAttName(uniquememberName,
                    jbStaticName);

            if (jbDynamicName == null)
            {
                jbDynamicName = "opiam.admin.faare.persistence.javabeans.JBDynamicGroup";
            }

//DW/2618/BeginPatch
            String memberUrlLdapAtt = null;
            String[] dynamicGroupObjectClass = null;
            StringBuffer dynamicGroupObjectClassFilter = null;
            String[] dynamicGroupAtt = null;

            if (memberUrlName != null)
            {
                _logger.debug("getGroupsAdmin jbDynamicName : " + jbDynamicName);

                memberUrlLdapAtt = LdapUtil.convertJBAttrNameToLdapAttName(memberUrlName,
                        jbDynamicName);

                // build a dynamic group tab
                dynamicGroupObjectClass = PropertiesManager.getInstance()
                                                                .getPersistenceDescriptionMap()
                                                                .getClassDescriptor(jbDynamicName)
                                                                .getObjectClassValues();
                dynamicGroupObjectClassFilter = new StringBuffer();

                for (int i = 0; i < dynamicGroupObjectClass.length; i++)
                {
                    dynamicGroupObjectClassFilter.append("(objectclass=" +
                    dynamicGroupObjectClass[i] + ")");
                }

                dynamicGroupAtt = new String[1];
                dynamicGroupAtt[0] = memberUrlLdapAtt;
            }
//DW/2618/EndPatch

            String[] staticGroupObjectClass = PropertiesManager.getInstance()
                                                               .getPersistenceDescriptionMap()
                                                               .getClassDescriptor(jbStaticName)
                                                               .getObjectClassValues();
            StringBuffer staticGroupObjectClassFilter = new StringBuffer();

            for (int i = 0; i < staticGroupObjectClass.length; i++)
            {
                staticGroupObjectClassFilter.append("(objectclass=" +
                    staticGroupObjectClass[i] + ")");
            }

            String[] staticGroupAtt = new String[1];
            staticGroupAtt[0] = uniquemberLdapAtt;

//DW/2618/BeginPatch
            LDAPSearchResults res = null;
            //DW/2659/BeginPatch
            //if (memberUrlName != null)
            if ((memberUrlName != null) && (dynamicGroupAtt[0] != null))
            //DW/2659/EndPatch
            {
                //Etape1: recherche des groupes dynamiques
                res = appliLd.search(baseDN,
                        LDAPConnection.SCOPE_SUB,
                        "(&" + dynamicGroupObjectClassFilter.toString() + "(" +
                        dynamicGroupAtt[0] + "=*))", dynamicGroupAtt, false);

                _logger.debug(
                    "getGroupsAdmin nbre de groupes dynamiques trouves : " +
                    res.getCount());
            }
            //DW/2659/BeginPatch
//DW/2664/BeginPatch
            //else if (dynamicGroupAtt[0] == null)
            else if ((dynamicGroupAtt != null) && (dynamicGroupAtt[0] == null))
//DW/2664/EndPatch
            {
                _logger.debug("getGroupsAdmin dynamicGroupAtt[0] is null");
            }
            //DW/2659/EndPatch
//DW/2620/BeginPatch
            //DynamicGroup[] dynGroupTab = null;
            JBDynamicGroup[] dynGroupTab = null;
//DW/2620/EndPatch
//DW/2618/EndPatch

            //Etape2: pour chaque groupe dynamique trouv�, on cr�e un objet DynamicGroup
            if (res != null)
            {
//DW/2620/BeginPatch
                //dynGroupTab = new DynamicGroup[res.getCount()];
                dynGroupTab = new JBDynamicGroup[res.getCount()];
//DW/2620/EndPatch

                Object o = null;
                int i = 0;

                while (res.hasMoreElements())
                {
                    o = res.nextElement();

                    if (o != null)
                    {
                        if (o instanceof LDAPEntry)
                        {
//DW/2620/BeginPatch
/*
                            dynGroupTab[i] = new DynamicGroup(((LDAPEntry) o).getDN(),
                                    ((LDAPEntry) o).getAttribute(
                                        dynamicGroupAtt[0]).getStringValueArray()[0]);
*/
                            dynGroupTab[i] = new JBDynamicGroup();
                            dynGroupTab[i].setDn(((LDAPEntry) o).getDN());
                            dynGroupTab[i].setMemberUrl(((LDAPEntry) o).getAttribute(
                                        dynamicGroupAtt[0]).getStringValueArray()[0]);
//DW/2620/EndPatch
                        }
                    }

                    i++;
                }
            }
            else
            {
//DW/2620/BeginPatch
                //dynGroupTab = new DynamicGroup[0];
                dynGroupTab = new JBDynamicGroup[0];
//DW/2620/EndPatch
            }

            v.add(dn);

            int beg = 0;
            int end = 0;
            int oldsize = 1;
            boolean cont = true;

            do
            {
                for (int i = beg; i <= end; i++)
                {
                    _logger.debug("getGroupsAdmin i : " + i);

                    String dni = LdapUtil.formatDN((String) v.get(i))
                                         .toLowerCase();
                    _logger.debug("getGroupsAdmin dni : " + dni);

                    //DW/2659/BeginPatch
                    if (staticGroupAtt[0] == null)
                    {
                        _logger.debug("getGroupsAdmin staticGroupAtt[0] is null");
                    }
                    else
                    {
                        // static groups
                        res = appliLd.search(baseDN, LDAPConnection.SCOPE_SUB,
                            "(&" + staticGroupObjectClassFilter.toString() +
                            "(" + staticGroupAtt[0] + "=" + dni + "))",
                            staticGroupAtt, false);

                        _logger.debug(
                                "getGroupsAdmin nbre de groupes statiques trouves : " +
                                res.getCount());
                    }
                    //DW/2659/EndPatch

                    if (res != null)
                    {
                        Object o = null;
                        int j = 0;

                        while (res.hasMoreElements())
                        {
                            o = res.nextElement();

                            if (o != null)
                            {
                                if (o instanceof LDAPEntry)
                                {
                                    String dnj = LdapUtil.formatDN(((LDAPEntry) o).getDN())
                                                         .toLowerCase();
                                    _logger.debug("getGroupsAdmin dnj : " +
                                        dnj);

                                    boolean found = false;

                                    //On regarde si le DN du groupe statique trouv� est dans le vecteur v
                                    for (int k = 0; k < v.size(); k++)
                                    {
                                        if (((String) v.get(k)).equals(dnj))
                                        {
                                            found = true;
                                        }
                                    }

                                    if (!found)
                                    {
                                        _logger.debug("getGroupsAdmin found : " +
                                            found);
                                        v.add(dnj);
                                    }
                                }
                            }

                            j++;
                        }
                    }

                    String utlTest = null;

                    // Parcours des groupes dynamiques
                    for (int j = 0; j < dynGroupTab.length; j++)
                    {
                        //r�cup�ration le l'url LDAP du groupe dynamique
//DW/2620/BeginPatch
                        utlTest = dynGroupTab[j].getMemberUrl();
                        //utlTest = dynGroupTab[j].getLdapUrl();
//DW/2620/EndPatch
                        _logger.debug("getGroups utlTest : " + utlTest);

                        LDAPUrl url = new LDAPUrl(utlTest);
                        String base = LdapUtil.formatDN(url.getDN())
                                              .toLowerCase();
                        String dnj = LdapUtil.formatDN(dynGroupTab[j].getDn())
                                             .toLowerCase();

                        // compare URL dn and dni
                        if (dni.indexOf(base) > -1)
                        {
                            if ((url.getScope() == LDAPConnection.SCOPE_SUB) ||
                                    ((url.getScope() == LDAPConnection.SCOPE_ONE) &&
                                    (LDAPDN.explodeDN(dni, false).length == (LDAPDN.explodeDN(
                                        base, false).length + 1))))
                            {
                                try
                                {
                                	/*AMVOU/BeginPatch 29/08/2012
                                	if (appliLd.search(dni, LDAPConnection.SCOPE_BASE,
                                                url.getFilter(),
                                                _attrsSelected, false) != null)*/                                	
                                	LDAPSearchResults ldsr = appliLd.search(dni, LDAPConnection.SCOPE_BASE, url.getFilter(), _attrsSelected, false);
                                    if ( ldsr != null && ldsr.getCount()>0)
                                    //AMVOU/EndPatch
                                    {
                                        boolean found = false;

                                        for (int k = 0; k < v.size(); k++)
                                        {
                                            if (((String) v.get(k)).equals(dnj))
                                            {
                                                found = true;
                                            }
                                        }

                                        if (!found)
                                        {
                                            v.add(dnj);
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }

                if (oldsize == v.size())
                {
                    cont = false;
                }
                else
                {
                    oldsize = v.size();
                    beg = end + 1;
                    end = oldsize - 1;
                }
            }
            while (cont);

            v.remove(dn);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return v;
    }

    /**
     * Checks whether a search request with given filter has results.
     *
     * @param filter Search filter.
     * @param userContext Current user context.
     *
     * @return true if it has, false if it has not.
     *
     * @throws PersistenceException in case of null argument.
     */
    public static boolean hasResults(String filter, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------HASRESULTS DEBUT--------------");

        if (filter == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        boolean hasResults = false;

        try
        {
            LDAPConnection ld = userContext.getLd();
            LDAPSearchResults res = ld.search(userContext.getLdapConfig()
                                                         .getBaseDN(),
                    LDAPConnection.SCOPE_SUB, filter, _attrsSelected, false);

            if (res.hasMoreElements())
            {
                hasResults = true;
            }
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
        }

        return hasResults;
    }

    //-- hasResults

    /**
    * Internally performs a search.
    *
    * @param ld LDAP connection.
    * @param scope Search sccope.
    * @param filter Search filter.
    * @param atts Requested attributes.
    * @param base Search base.
    * @param jbClassDescriptor Object class descriptor or null.
    * @param userContext Current user context.
    *
    * @return SearchResult Entries.
    *
    * @throws PersistenceException from internalSearch(same + String[])
    */
    private static SearchResult internalSearch(LDAPConnection ld, int scope,
        String filter, String[] atts, String base,
        JBClassDescriptor jbClassDescriptor, UserContext userContext)
        throws PersistenceException//DW/2584/BeginPatch
    {
        return internalSearch(ld, scope, filter, atts, base, jbClassDescriptor,
            userContext, null);
    }

    //DW/2595 : sortField devient un tableau

    /**
    * Internally performs a search.
    *
    * @param ld LDAP connection.
    * @param scope Search sccope.
    * @param filter Search filter.
    * @param atts Requested attributes.
    * @param base Search base.
    * @param jbClassDescriptor Object class descriptor or null.
    * @param userContext Current user context.
    * @param sortFields Fields on which results must be sorted.
    *        Sort is performed by directory servers if possible.
    *
    * @return SearchResult Entries.
    *
    * @throws PersistenceException in case of null argument or LDAP error.
    */
    private static SearchResult internalSearch(LDAPConnection ld, int scope,
        String filter, String[] atts, String base,
        JBClassDescriptor jbClassDescriptor, UserContext userContext,
        String[] sortFields) throws PersistenceException//DW/2584/EndPatch
    {
        _logger.debug("-----------INTERNALSEARCH3 DEBUT--------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "internalSearch",
                    "PersistenceLDAP"));
        }

        if (filter == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "filter", "internalSearch",
                    "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "internalSearch",
                    "PersistenceLDAP"));
        }

        SearchResult result = new SearchResult();
        result.setSizeLimit(false);

        List returnedResult = new ArrayList();

        if (atts == null)
        {
            atts = _attrsSelected;
        }

        if (base == null)
        {
            base = userContext.getLdapConfig().getBaseDN();
        }

//DW/2601/BeginPatch
/*
        if (scope == 0)
        {
            scope = LDAPConnection.SCOPE_SUB;
        }
*/
//DW/2601/EndPatch

        //DW/2584/BeginPatch
        _logger.debug("INTERNALSEARCH3 jbClassDescriptor " +
            ((jbClassDescriptor == null) ? "null" : jbClassDescriptor.getName()));

        LDAPSearchConstraints cons = null;

        if ((sortFields != null) && (sortFields.length > 0) &&
                (jbClassDescriptor != null))
        {
            cons = new LDAPSearchConstraints();

            LDAPSortKey[] sortKeys = new LDAPSortKey[sortFields.length];
            int cnt = 0;

            for (int i = 0; i < sortFields.length; i++)
            {
                _logger.debug("INTERNALSEARCH3 sortField " + sortFields[i]);

                String attname = jbClassDescriptor.getSourceAttributeName(sortFields[i]);
                _logger.debug("INTERNALSEARCH3 attname " + attname);

                if (attname != null)
                {
                    sortKeys[cnt] = new LDAPSortKey(attname);
                    cnt++;
                }
            }

            if (cnt > 0)
            {
                LDAPSortControl sortCtrl = new LDAPSortControl(sortKeys, true);
                cons.setServerControls(sortCtrl);
            }
        }

        //DW/2584/EndPatch
        try
        {
            _logger.debug("INTERNALSEARCH3 base " + base);
            _logger.debug("INTERNALSEARCH3 scope " + scope);
            _logger.debug("INTERNALSEARCH3 filter " + filter);

            //DW/2584/BeginPatch
            //LDAPSearchResults res = ld.search(base, scope, filter, atts, false);
            LDAPSearchResults res = ld.search(base, scope, filter, atts, false,
                    cons);

            //DW/2584/EndPatch
            LDAPEntry entry = null;
            JBTop jbTop = null;
            Object o = null;

            _logger.debug("INTERNALSEARCH3 res.getCount() : " + res.getCount());
            _logger.debug("INTERNALSEARCH3 res.hasMoreElements() : " +
                res.hasMoreElements());

            //Parcours des r�sultats
            while (res.hasMoreElements())
            {
                o = res.nextElement();

                if (o != null)
                {
                    if (o instanceof LDAPEntry)
                    {
                        try
                        {
                            _logger.debug(
                                "INTERNALSEARCH3 ((LDAPEntry) o).getDN() : " +
                                ((LDAPEntry) o).getDN());
                            jbTop = internalSearch(ld, (LDAPEntry) o,
                                    jbClassDescriptor, userContext);

                            if (jbTop != null)
                            {
                                returnedResult.add(jbTop);
                            }
                        }
                        catch (PersistenceException pee)
                        {
                            _logger.error(MessageUtil.formatMessage(
                                    "MSG_MAPPING_OBJECTCLASS_NOT_FOUND"));
                        }
                    }
                    else if (o instanceof LDAPException)
                    {
                        result.setSizeLimit(true);
                    }
                    else if (o instanceof LDAPReferralException)
                    {
                        //Exception mal g�r�e!!!!!!!!!
                        result.setSizeLimit(true);
                    }
                }
            }

            result.setLResults(returnedResult);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * Loads a business bean object from an entry read from directory server.
     *
     * @param ld LDAP connection
     * @param entry LDAP entry!
     * @param jbClassDescriptor Object class descriptor or null.
     * @param userContext Current user context
     *
     * @return Generated business bean object. Null if jbClassDescriptor is not null and
     *         entry does not match corresponding object definition.
     * @throws PersistenceException in case of null argument or from internalLoad.
     */
    private static JBTop internalSearch(LDAPConnection ld, LDAPEntry entry,
        JBClassDescriptor jbClassDescriptor, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------INTERNALSEARCH2 DEBUT -----------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "internalSearch",
                    "PersistenceLDAP"));
        }

        if (entry == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "entry", "internalSearch",
                    "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "internalSearch",
                    "PersistenceLDAP"));
        }

        JBTop jbTop = null;

        try
        {
            //Si un jbClassDescriptor est demand� on regarde si l'objet qui doit �tre
            // retourn� est bien du type jbClassDescriptor envoy�
            if ((jbClassDescriptor != null) &&
                    jbClassDescriptor.getMapTo().isFullySpecified())
            {
                _logger.debug(
                    "INTERNALSEARCH2 jbClassDescriptor.getMapTo().getLdapoc() : " +
                    jbClassDescriptor.getMapTo().getLdapoc());
                _logger.debug(
                    "INTERNALSEARCH2 jbClassDescriptor.getMapTo().isFullySpecified() : " +
                    jbClassDescriptor.getMapTo().isFullySpecified());

                HashSet h1 = (HashSet) jbClassDescriptor.getMapTo()
                                                        .getLdapocSet();
                Enumeration enum1 = entry.getAttribute("objectclass")
                                        .getStringValues();
                HashSet h = new HashSet();

                while (enum1.hasMoreElements())
                {
                    h.add(((String) enum1.nextElement()).toLowerCase().trim());
                }

                if (!h1.equals(h))
                {
                    _logger.debug("INTERNALSEARCH2 h1.equals(h) false");

                    return null;
                }
            }

            //Contr�le cache
            Map hCache = userContext.getCache();
            jbTop = (JBTop) getFromCache(entry.getDN(), hCache);

            _logger.debug("INTERNALSEARCH2 entry.getDN() : " + entry.getDN());

            if ((jbTop != null) &&
                //DW/2577//BeginPatch
                (jbTop.getModify() != null) &&
                //DW/2577//EndPatch
                jbTop.getModify().equals(LdapUtil.getModifyFromLDAPEntry(entry)))
            {
                _logger.debug("trouve dans le cache");

                //Cas o� l'objet recherch� est dans le cache et n'a pas �t� modifi�: on le renvoie
                return jbTop;
            }
            else if ((jbTop != null) &&
                //DW/2577//BeginPatch
                ((jbTop.getModify() == null) ||
                //DW/2577//EndPatch
                !jbTop.getModify().equals(LdapUtil.getModifyFromLDAPEntry(
                //DW/2577//BeginPatch
                entry))))
            {
                //DW/2577//EndPatch
                _logger.debug("INTERNALSEARCH2 jbTop.getModify(): " +
                    jbTop.getModify());
                _logger.debug(
                    "INTERNALSEARCH2 getModifyFromLDAPEntry(entry) : " +
                    LdapUtil.getModifyFromLDAPEntry(entry));
                _logger.debug(
                    "INTERNALSEARCH2 objet en cache mais date de modif changee");
                jbTop = internalLoad(ld, entry, jbClassDescriptor, userContext);
                replaceInCache(jbTop, hCache);
            }
            else
            {
                jbTop = internalLoad(ld, entry, jbClassDescriptor, userContext);
                addToCache(jbTop, hCache, userContext);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return jbTop;
    }

    //internalSearch

    /**
     * Internally loads a business bean object from a dname, as
     * configured in faare_mapping.xml.
     *
     * @param ld LDAP connection.
     * @param dn Entry dname.
     * @param userContext Current user context.
     *
     * @return Generated business bean object.
     *
     * @throws PersistenceException in case of null argument or
     *    from internalLoad(LDAPConnection,String,JBClassDescriptor,UserContext)
     */
    private static JBTop internalLoad(LDAPConnection ld, String dn,
        UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------INTERNALLOAD1 DEBUT--------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "internalLoad", "PersistenceLDAP"));
        }

        if (dn == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "dn", "internalLoad", "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "internalLoad",
                    "PersistenceLDAP"));
        }

        _logger.debug("-----------INTERNALLOAD1 dn : " + dn);

        JBTop jbTop = null;

        try
        {
            LDAPEntry entry = ld.read(dn, _attrsSelected);

            return internalLoad(ld, entry, null, userContext);
        }
        catch (LDAPException le)
        {
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));
        }

        return null;
    }

    //internalLoad

    /**
     * Internally loads a business bean object from a dname, as
     * configured in faare_mapping.xml.
     *
     * @param ld LDAP connection.
     * @param entry LDAP entry.
     * @param jbClassDescriptor Not used.
     * @param userContext Current user context.
     *
     * @return Generated business bean object.
     *
     * @throws PersistenceException in case of null argument or configuration error.
     */
    private static JBTop internalLoad(LDAPConnection ld, LDAPEntry entry,
        JBClassDescriptor jbClassDescriptor, UserContext userContext)
        throws PersistenceException
    {
        //La notion de persistence SQL a �t� incorpor�e dans cette m�thode
        _logger.debug("-----------INTERNALLOAD2 DEBUT--------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "internalLoad", "PersistenceLDAP"));
        }

        if (entry == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "entry", "internalLoad",
                    "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "internalLoad",
                    "PersistenceLDAP"));
        }

        JBTop jbTop = null;

        try
        {
            /*R�cup�ration du DN de l'entr�e*/
            String dn = entry.getDN();

            _logger.debug("INTERNALLOAD2 1 dn : " + dn);

            _logger.debug("INTERNALLOAD2 2 entry : " + entry);

            _logger.debug("INTERNALLOAD2 3 entry.getAttribute(objectclass) : " +
                entry.getAttribute("objectclass"));

            String modifyTimestamp = LdapUtil.getModifyFromLDAPEntry(entry);

            //R�solution du pb d'Active Directory
            if (entry.getAttribute(_objectclassLdap) == null)
            {
                try
                {
                    entry = ld.read(dn, _attrsWithoutModifyTimestamp);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }

            /*R�cup�ration de la classe d'objet m�tier correspondant � cette entr�e LDAP*/
            Class cl = PropertiesManager.getInstance()
                                        .getPersistenceDescriptionMap()
                                        .getClass(entry.getAttribute(
                        "objectclass").getStringValues());

            _logger.debug("INTERNALLOAD2 2 cl : " + cl);

            /*Cr�ation de l'objet m�tier*/
            jbTop = (JBTop) cl.newInstance();

            /*Initialisation du DN*/
            jbTop.setDn(LdapUtil.formatDN(dn));

            /*Initialisation de la date de derniere modification*/
            jbTop.setModify(modifyTimestamp);

            /*R�cup�ration du ClassDescriptor*/
            JBClassDescriptor classDesc = PropertiesManager.getInstance()
                                                           .getPersistenceDescriptionMap()
                                                           .getClassDescriptor(cl.getName());

            LazyCollection lazyCollection = null;

            /*Indique si l'attribut est de type collection*/
            boolean isCollection;

            /*Indique s'il existe un attribut � chercher dans une BD*/
            boolean hasSQLAttr = false;

            /*Parcours de tous les attributs d�finis dans le mapping*/
            LDAPAttribute ldapAttr = null;
            JBFieldDescriptor fieldDesc = null;
            Iterator it = classDesc.getFields().iterator();

            while (it.hasNext())
            {
                fieldDesc = (JBFieldDescriptor) it.next();
                _logger.debug("internalLoad2 traitement de champ " +
                    fieldDesc.getName() + " iscollection = " +
                    fieldDesc.isACollection());

                /*On v�rifie que le champ n'est pas de type sql*/

                if (fieldDesc.getSrcDesc().getType() == null)
                {
                    /*R�cup�ration de l'attribut LDAP*/
                    ldapAttr = entry.getAttribute(fieldDesc.getSrcDesc()
                                                           .getName());

                    _logger.debug("internalLoad2 ldapAttr = " + ldapAttr);

                    if (ldapAttr == null)
                    {
                        try
                        {
                            if (fieldDesc.isACollection() &&
                                    fieldDesc.isALazy())
                            {
                                _logger.debug(
                                    "internalLoad2 creation de lazycollection pour champ " +
                                    fieldDesc.getName());

                                Class lazyClass = Class.forName(fieldDesc.getLazy());
                                Class[] cls =
                                {
                                    String.class, ArrayList.class,
                                    UserContext.class
                                };
                                List list = new ArrayList();

                                //list.add(fieldDesc.getName());
                                list.add(classDesc.getSourceAttributeName(
                                        fieldDesc.getName()));

                                Object[] objs = {dn, list, userContext};

                                Constructor constr = lazyClass.getDeclaredConstructor(cls);

                                lazyCollection = (LazyCollection) constr.newInstance(objs);

                                LdapUtil.setFieldValue(fieldDesc, jbTop,
                                    lazyCollection);
                            }
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }

                        // si l'entree ne contient pas l'attribut, continuer
                        // avec d'autres attributs
                        continue;
                    }

                    if (!fieldDesc.isACollection())
                    {
                        _logger.debug(
                            "internalLoad2 attribut n'est pas une collection ");

                        /*L'attribut n'est pas une collection*/
                        LdapUtil.setFieldValue(fieldDesc, jbTop,
                            getValue(ld, ldapAttr, fieldDesc, userContext));
                    }
                    else
                    { /*L'attribut est une collection*/
                        _logger.debug("internalLoad2 attribut collection ");

                        if (fieldDesc.isALazy())
                        {
                            _logger.debug("internalLoad2 lazy loading ");

                            /*Lazy loading demand� pour cette collection*/
                            if (fieldDesc.isStringType())
                            {
                                /*Premier type de lazy loading*/
                                try
                                {
                                    Class lazyClass = Class.forName(fieldDesc.getLazy());
                                    Class[] cls =
                                    {
                                        String.class, ArrayList.class,
                                        UserContext.class
                                    };
                                    List list = new ArrayList();

                                    //list.add(fieldDesc.getName());
                                    list.add(classDesc.getSourceAttributeName(
                                            fieldDesc.getName()));

                                    Object[] objs = {dn, list, userContext};

                                    Constructor constr = lazyClass.getDeclaredConstructor(cls);

                                    lazyCollection = (LazyCollection) constr.newInstance(objs);
                                }
                                catch (Exception e)
                                {
                                    e.printStackTrace();
                                }

                                LdapUtil.setFieldValue(fieldDesc, jbTop,
                                    lazyCollection);
                            }
                            else if (fieldDesc.isByteType())
                            {
                                _logger.debug(
                                    "internalLoad2 lazy loading pour bytes");

                                try
                                {
                                    Class lazyClass = Class.forName(fieldDesc.getLazy());
                                    Class[] cls =
                                    {
                                        String.class, ArrayList.class,
                                        UserContext.class
                                    };
                                    List list = new ArrayList();

                                    list.add(classDesc.getSourceAttributeName(
                                            fieldDesc.getName()));

                                    Object[] objs = {dn, list, userContext};

                                    Constructor constr = lazyClass.getDeclaredConstructor(cls);

                                    lazyCollection = (LazyCollection) constr.newInstance(objs);
                                }
                                catch (Exception e)
                                {
                                    e.printStackTrace();
                                }

                                LdapUtil.setFieldValue(fieldDesc, jbTop,
                                    lazyCollection);
                            }
                            else if (fieldDesc.isJBTopType())
                            {
                                /*Deuxi�me type de lazy loading*/
                                try
                                {
                                    Class lazyClass = Class.forName(fieldDesc.getLazy());
                                    _logger.debug("internalLoad2 lazyClass : " +
                                        fieldDesc.getLazy());

                                    Class[] cls =
                                    {
                                        String.class, ArrayList.class,
                                        UserContext.class
                                    };
                                    List list = new ArrayList();

                                    list.add(classDesc.getSourceAttributeName(
                                            fieldDesc.getName()));

                                    Object[] objs = {dn, list, userContext};

                                    Constructor constr = lazyClass.getDeclaredConstructor(cls);

                                    lazyCollection = (LazyCollection) constr.newInstance(objs);
                                }
                                catch (Exception e)
                                {
                                    e.printStackTrace();
                                }

                                _logger.debug(
                                    "internalLoad2 fieldDesc.getName() : " +
                                    fieldDesc.getName());
                                _logger.debug("internalLoad2 jbTop.getDn() : " +
                                    jbTop.getDn());

                                LdapUtil.setFieldValue(fieldDesc, jbTop,
                                    lazyCollection);
                            }
                        }
                        else
                        {
                            _logger.debug("internalLoad2 pas lazy loading ");

                            /*Lazy loading PAS demand� pour cette collection*/
                            Enumeration attrEnum = getValueCollection(ld,
                                    ldapAttr, fieldDesc, userContext);

                            LdapUtil.setCollFieldValue(fieldDesc, jbTop,
                                attrEnum);
                        }
                    }
                }
                else
                {
                    /*L'attribut est de type SQL on va le traiter ensuite*/
                    hasSQLAttr = true;
                }
            }

            // end while
/*
            if (hasSQLAttr)
            {
                //NOT YET IMPLEMENTED: internalLoadSQL(classDesc, cl, jbTop);
            }
*/

            //La m�thode compute() permet d'impl�menter les attributs calcul�s
            jbTop.compute();
        }
        catch (InstantiationException ie)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_INSTANTIATION_PROBLEM", ie.toString()), ie);
        }
        catch (IllegalAccessException iae)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ILLEGAL_ACCESS_PROBLEM", iae.toString()), iae);
        }

        return jbTop;
    }

    /**
     * Internally modifies an entry corresponding to a modified business bean object.
     *
     * @param ld LDAP Connection.
     * @param jbTop Business bean object.
     * @param jbOldObj Business bean object before modification, in case the modified
     *        object was cloned.
     * @param userContext Current user context.
     *
     * @throws PersistenceException in case of null argument or LDAP error.
     */
//DW/2633/BeginPatch
    private static void internalModify(LDAPConnection ld, JBTop jbTop, JBTop jbOldObj,
        UserContext userContext) throws PersistenceException
    {
//DW/2633/EndPatch
//DW/2662/BeginPatch
        boolean isRename = false;
        String newRdn = null;
//DW/2662/EndPatch

        _logger.debug("-----------INTERNALMODIFY1 DEBUT--------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "internalModify",
                    "PersistenceLDAP"));
        }

        if (jbTop == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "jbTop", "internalModify",
                    "PersistenceLDAP"));
        }

        if (jbTop.getDn() == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "jbTop.getDn()", "internalModify",
                    "PersistenceLDAP"));
        }

        try
        {
            _logger.debug("INTERNALMODIFY1 jbTop.getDn() : " + jbTop.getDn());

//DW/2633/BeginPatch
            LDAPEntry entry = null;

            if (jbOldObj == null)
            {
                /*R�cup�ration de l'entr�e LDAP correspondante*/
                entry = ld.read(jbTop.getDn(), _attrsSelected);
            }
//DW/2633/EndPatch

            /*R�cup�ration du type d'objet m�tier*/
            JBClassDescriptor classDesc = PropertiesManager.getInstance()
                                                           .getPersistenceDescriptionMap()
                                                           .getClassDescriptor(jbTop.getClass()
                                                                                    .getName());

            /*Nouvel attribut LDAP*/
            LDAPAttribute ldapAttr = null;

            /*Ancien attribut LDAP*/
            LDAPAttribute oldLdapAttr = null;

            /*Liste des modifications*/
            LDAPModificationSet ldapModificationSet = new LDAPModificationSet();

            /*Parcours des attributs*/
            JBFieldDescriptor fieldDesc = null;
            Iterator it = classDesc.getFields().iterator();

            while (it.hasNext())
            {
                fieldDesc = (JBFieldDescriptor) it.next();
                _logger.debug("INTERNALMODIFY1 fieldDesc.getName() : " +
                    fieldDesc.getName());

                if (fieldDesc.getSrcDesc().getName().compareToIgnoreCase("dn") == 0)
                {
                    // ne pas traiter l'attribut "DN" (ce n'est pas un atttribut)
                    continue;
                }

                if (fieldDesc.getSrcDesc().getName().equalsIgnoreCase("objectclass"))
                {
                    _logger.debug(
                        "INTERNALMODIFY1 on ignore pour l'instant les modifs sur objectclass");
//DW/2633/BeginPatch
                //} else {
                // Cas ou l'application n'a pas clone l'objet : on compare avec l'entree dans l'annuaire
                }
                else  if (jbOldObj == null)
                {
//DW/2633/EndPatch
                    /*R�cup�ration de la nouvelle valeur*/
                    ldapAttr = LdapUtil.getLDAPAttrFromFieldDesc(fieldDesc,
                            jbTop);

                    _logger.debug("INTERNALMODIFY1 entry : " + entry);

                    /*R�cup�ration de l'ancienne valeur*/
                    oldLdapAttr = entry.getAttribute(fieldDesc.getSrcDesc()
                                                              .getName());

                    if ((ldapAttr != null) && (oldLdapAttr != null))
                    {
                        _logger.debug(
                            "INTERNALMODIFY1 Cas1: l'ancienne et la nouvelle valeurs " +
                            "ne sont pas nulles pour fieldDesc.getName() : " +
                            fieldDesc.getName());

                        //MODIF CCT 11/05/04 Correction du bug qui envoyait ts les attributs � modifier

                        /*Cas1: l'ancienne et la nouvelle valeurs ne sont pas nulles*/
                        boolean replace = true;

                        if ((fieldDesc.isACollection() &&
                                !fieldDesc.isByteType()) ||
                                (fieldDesc.isALazy() &&
                                !fieldDesc.isByteType()))
                        {
                            _logger.debug(
                                "INTERNALMODIFY1 Cas1: type collection ");

                            if (StringUtil.compareStringEnumeration(
                                        ldapAttr.getStringValues(),
                                        oldLdapAttr.getStringValues()) == 0)
                            {
                                _logger.debug(
                                    "INTERNALMODIFY1 Cas1: type collection �gaux");
                                replace = false;
                            }
                        }
                        else if (fieldDesc.isStringType() ||
                                fieldDesc.isIntegerType() ||
                                fieldDesc.isJBTopType())
                        {
                            _logger.debug("INTERNALMODIFY1 Cas1: type string");

                            if (ldapAttr.getStringValueArray()[0].compareTo(
                                        oldLdapAttr.getStringValueArray()[0]) == 0)
                            {
                                _logger.debug(
                                    "INTERNALMODIFY1 Cas1: type string �gaux");
                                replace = false;
                            }
//DW/2662/BeginPatch
                            else
                            {
                               String dn = jbTop.getDn().toLowerCase();
                               String attname = fieldDesc.getSrcDesc().getName().toLowerCase();

                               if (dn.startsWith(attname + "=") ||
                                   dn.startsWith(attname + " ="))
                               {
                                  isRename = true;
                                  newRdn = attname + "=" + ldapAttr.getStringValueArray()[0];
                                  _logger.debug("INTERNALMODIFY1 Cas1: change RDN");
                                  replace = false;
                               }
                            }
//DW/2662/EndPatch

                        }
                        else if (fieldDesc.isByteType())
                        {
                            _logger.debug(
                                "INTERNALMODIFY1 Cas1: type binaries ");

                            Enumeration enum1 = ldapAttr.getByteValues();
                            Enumeration enumOld = oldLdapAttr.getByteValues();
                            boolean equal = true;

                            while (enum1.hasMoreElements() &&
                                    enumOld.hasMoreElements() && equal)
                            {
                                if (!Arrays.equals(
                                            (byte[]) enum1.nextElement(),
                                            (byte[]) enumOld.nextElement()))
                                {
                                    equal = false;
                                }
                            }

                            if (equal)
                            {
                                _logger.debug(
                                    "INTERNALMODIFY1 Cas1: type binaries �gaux");
                                replace = false;
                            }
                            else
                            {
                                _logger.debug(
                                    "INTERNALMODIFY1 Cas1: type binaries pas �gaux");
                            }
                        }

                        if (replace)
                        {
                            _logger.debug("INTERNALMODIFY1 Cas1: modification");
                            ldapModificationSet.add(LDAPModification.REPLACE,
                                ldapAttr);
                        }
                    }
                    else if ((ldapAttr != null) && (oldLdapAttr == null))
                    {
                        _logger.debug(
                            "INTERNALMODIFY1 Cas2: L'ancienne valeur est nulle, pas la nouvelle : " +
                            fieldDesc.getName());

                        /*Cas2: L'ancienne valeur est nulle, pas la nouvelle*/
                        /*DW/2548*/
                        /*BeginPatch*/
                        ldapModificationSet.add(LDAPModification.REPLACE,
                            ldapAttr);

                        /*DW/2548*/
                        /*EndPatch*/
                    }
                    else if ((ldapAttr == null) && (oldLdapAttr != null))
                    {
                        _logger.debug(
                            "INTERNALMODIFY1 Cas3: La nouvelle valeur est nulle, pas l'ancienne : " +
                            fieldDesc.getName());

                        /*Cas3: La nouvelle valeur est nulle, pas l'ancienne*/
//DW/2628/BeginPatch
                        /* no need to specify values, remove all values. */
                        ldapModificationSet.add(LDAPModification.DELETE,
                            new LDAPAttribute(oldLdapAttr.getName()));
//DW/2628/EndPatch
                    }
                }
//DW/2633/BeginPatch
                // Cas ou l'application a clone l'objet : on compare avec l'objet original
                else
                {
                   Object newValue;
                   Object oldValue;
                   try
                   {
                       newValue = PropertyUtils.getProperty(jbTop, fieldDesc.getName());
                   }
                   catch (Exception ex) // no value
                   {
                       newValue = null;
                   }
                   try
                   {
                       oldValue = PropertyUtils.getProperty(jbOldObj, fieldDesc.getName());
                   }
                   catch (Exception ex) // no value
                   {
                       oldValue = null;
                   }
                   _logger.debug(fieldDesc.getName() + "=>" + newValue + "/" + oldValue);
                   // cas des chaines vides.
                   if (fieldDesc.isStringType() && !fieldDesc.isACollection())
                   {
                       String snew = (String) newValue;
                       String sold = (String) oldValue;

                       if (snew != null)
                       {
                           snew = snew.trim();
                           if (snew.equals(""))
                           {
                               newValue = null;
                           }
                       }
                       if (sold != null)
                       {
                           sold = sold.trim();
                           if (sold.equals(""))
                           {
                               oldValue = null;
                           }
                       }
                   }
                   if ((newValue == null) && (oldValue == null))
                   {
                       continue;
                   }
                   ldapAttr =
                        LdapUtil.getLDAPAttrFromFieldDesc(fieldDesc, jbTop);

                   if ((newValue == null) && (oldValue != null)) // deleted
                   {
                       _logger.debug(fieldDesc.getName() + "=> deleted");
                       //DW/2651/BeginPatch
                       //ldapModificationSet.add(LDAPModification.DELETE,  new LDAPAttribute(ldapAttr.getName()));
                       ldapModificationSet.add(LDAPModification.DELETE,
                               new LDAPAttribute(fieldDesc.getSrcDesc().getName()));
                       //DW/2651/EndPatch
                   }
                   else if ((newValue != null) && (oldValue == null)) // added
                   {
                       _logger.debug(fieldDesc.getName() + "=> added");
                       ldapModificationSet.add(LDAPModification.REPLACE, ldapAttr);
                   }
                   else if (!fieldDesc.isACollection())
                   {
                      if (!newValue.equals(oldValue)) // modified, simple value
                      {
//DW/2662/BeginPatch
                          String dn = jbTop.getDn().toLowerCase();
                          String attname = fieldDesc.getSrcDesc().getName().toLowerCase();

                          if (dn.startsWith(attname + "=") ||
                              dn.startsWith(attname + " ="))
                          {
                             isRename = true;
                             newRdn = attname + "=" + newValue;
                             _logger.debug(fieldDesc.getName() + "=> change RDN");
                          }
                          else
                          {
//DW/2662/EndPatch
                              _logger.debug(fieldDesc.getName() + "=> modified, simple value");
                              ldapModificationSet.add(LDAPModification.REPLACE, ldapAttr);
//DW/2662/BeginPatch
                          }
//DW/2662/EndPatch
                      }
                   }
                   else // Collection
                   {
                      //DW/2658/BeginPatch
                         if (((Collection) newValue).isEmpty() && (oldValue != null) &&
                             (!((Collection) oldValue).isEmpty()))
                         {
                        _logger.debug(fieldDesc.getName() + "=> deleted");
                        ldapModificationSet.add(LDAPModification.DELETE,
                                new LDAPAttribute(fieldDesc.getSrcDesc().getName()));

                         }
                         else if (!CollectionUtils.isEqualCollection((Collection) newValue, (Collection) oldValue))
                      {
                          _logger.debug(fieldDesc.getName() + "=> modified, collection");
                          ldapModificationSet.add(LDAPModification.REPLACE, ldapAttr);
                      }
                      //DW/2658/EndPatch
                   }
                }
//DW/2633/EndPatch
            }

            /*Lancement de la modification dans l'annuaire LDAP*/
            if (ldapModificationSet.size() != 0)
            {
                ld.modify(jbTop.getDn(), ldapModificationSet);

//DW/2633/BeginPatch
                if (jbOldObj == null)
                {
//DW/2633/EndPatch
                    /*Mise � jour de la date de modification dans l'objet m�tier*/
                    jbTop.setModify(LdapUtil.getModifyFromLDAPEntry(entry));
//DW/2633/BeginPatch
                }

                /*Mise � jour du cache*/
                //replaceInCache(jbTop, userContext.getCache());
//DW/2633/EndPatch
            }
//DW/2662/BeginPatch
            if (isRename)
            {
               String sDn = jbTop.getDn();
               ld.rename(sDn, newRdn, true);

               userContext.getCache().remove(jbTop.getDn());
               DN dn = new DN(sDn);
               DN pdn = dn.getParent();
               jbTop.setDn(newRdn + "," + pdn.toString());
            }
//DW/2662/EndPatch
        }
        catch (LDAPException le)
        {
            le.printStackTrace();
            _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                    LdapUtil.getLDAPErrorMessage(le)));

            /*DW/2547*/
            /*BeginPatch*/
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);

            /*DW/2547*/
            /*EndPatch*/
        }

        _logger.debug("-----------INTERNALMODIFY1 END --------------");
    }

    /**
     * Internally modifies an attribute from an entry corresponding to
     *  a modified business bean object.
     *
     * @param ld LDAP Connection.
     * @param jbTop Business bean object.
     * @param attribute business bean attribute name.
     * @param userContext Current user context.
     *
     * @throws PersistenceException in case of null argument or LDAP error.
     */
    private static void internalModify(LDAPConnection ld, JBTop jbTop,
        String attribute, UserContext userContext) throws PersistenceException
    {
        _logger.debug("-----------INTERNALMODIFY2 DEBUT--------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "internalModify",
                    "PersistenceLDAP"));
        }

        if (jbTop == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "jbTop", "internalModify",
                    "PersistenceLDAP"));
        }

        if (attribute == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "attribute", "internalModify",
                    "PersistenceLDAP"));
        }

        try
        {
            /*R�cup�ration de l'entr�e LDAP correspondant � l'objet m�tier*/
            LDAPEntry entry = ld.read(jbTop.getDn(), _attrsSelected);

            _logger.debug(" INTERNALMODIFY2 entry.getDN() : " + entry.getDN());

            /*R�cup�ration du ClassDescriptor de ce type d'objet m�tier*/
            JBClassDescriptor classDesc = PropertiesManager.getInstance()
                                                           .getPersistenceDescriptionMap()
                                                           .getClassDescriptor(jbTop.getClass()
                                                                                    .getName());

            LDAPAttribute ldapAttr = null;
            LDAPAttribute oldLdapAttr = null;
            LDAPModificationSet ldapModificationSet = new LDAPModificationSet();
            int i = 0;
            boolean found = false;

            /*Recherche de l'attribut envoy�*/
            JBFieldDescriptor fieldDesc = null;
            Iterator it = classDesc.getFields().iterator();

            _logger.debug(" INTERNALMODIFY2 1  ");

            while (it.hasNext() && !found)
            {
                _logger.debug(" INTERNALMODIFY2 2  ");
                fieldDesc = (JBFieldDescriptor) it.next();
                _logger.debug(
                    " INTERNALMODIFY2 2 fieldDesc.getSrcDesc().getName() :  " +
                    fieldDesc.getSrcDesc().getName());
                _logger.debug(" INTERNALMODIFY2 2 attribute :  " + attribute);

                if (fieldDesc.getName().trim().compareToIgnoreCase(attribute.trim()) == 0)
                {
                    found = true;
                    _logger.debug(" INTERNALMODIFY2 2 find");

                    /*R�cup�ration de la valeur modifi�e*/
                    ldapAttr = LdapUtil.getLDAPAttrFromFieldDesc(fieldDesc,
                            jbTop);
                    _logger.debug(" INTERNALMODIFY2 2 ldapAttr: " + ldapAttr);

                    /*R�cup�ration de la valeur avant modification dans l'annuaire*/
                    oldLdapAttr = entry.getAttribute(fieldDesc.getSrcDesc()
                                                              .getName());

                    _logger.debug(" INTERNALMODIFY2 2 oldLdapAttr: " +
                        oldLdapAttr);

                    if ((ldapAttr != null) && (oldLdapAttr != null))
                    {
                        /*Cas1: l'ancienne et la nouvelle valeurs ne sont pas nulles*/
                        ldapModificationSet.add(LDAPModification.REPLACE,
                            ldapAttr);
                    }
                    else if ((ldapAttr != null) && (oldLdapAttr == null))
                    {
                        /*Cas2: L'ancienne valeur est nulle, pas la nouvelle*/
                        /*DW/2548*/
                        /*BeginPatch*/

                        //ldapModificationSet.add(LDAPModification.ADD, ldapAttr);
                        ldapModificationSet.add(LDAPModification.REPLACE,
                            ldapAttr);

                        /*DW/2548*/
                        /*EndPatch*/
                    }
                    else if ((ldapAttr == null) && (oldLdapAttr != null))
                    {
                        /*Cas3: La nouvelle valeur est nulle, pas l'ancienne*/
//DW/2628/BeginPatch
                        /* no need to specify values, remove all values. */
                        ldapModificationSet.add(LDAPModification.DELETE,
                            new LDAPAttribute(oldLdapAttr.getName()));
//DW/2628/EndPatch
                    }
                }

                i++;
            }

            _logger.debug(" INTERNALMODIFY2 3  ");

            /*Lancement de la modification dans l'annuaire LDAP*/
            if (ldapModificationSet.size() != 0)
            {
                for (int k = 0; k < ldapModificationSet.size(); k++)
                {
                    LDAPModification ldapModif = ldapModificationSet.elementAt(k);
                    _logger.debug(
                        " INTERNALMODIFY2 3 ldapModif.getAttribute().getName() : " +
                        ldapModif.getAttribute().getName());

                    Enumeration enum1 = ldapModif.getAttribute().getStringValues();
                }

                ld.modify(jbTop.getDn(), ldapModificationSet);

                /*Mise � jour de la date de modification dans l'objet m�tier*/
                jbTop.setModify(LdapUtil.getModifyFromLDAPEntry(entry));

                /*Mise � jour du cache*/
                replaceInCache(jbTop, userContext.getCache());
            }

            _logger.debug(" INTERNALMODIFY2 4  ");

            /*DW/2547*/
            /*BeginPatch*/
        }
        catch (LDAPException le)
        {
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);

            /*DW/2547*/
            /*EndPatch*/
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * Copies properties from a cloned business bean object to original object.
     *
     * @param jbTop Original object.
     * @param jbTopClone Cloned object.
     *
     * @throws PersistenceException In case of null argument or
     *  PropertyUtils.copyProperties() error.
     */
    private static void transferFromClone(JBTop jbTop, JBTop jbTopClone)
        throws PersistenceException
    {
        _logger.debug("-----------TRANSFERFROMCLONE DEBUT--------------");

        if (jbTopClone == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "jbTopClone", "transferFromClone",
                    "PersistenceLDAP"));
        }

        if (jbTop == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "jbTop", "transferFromClone",
                    "PersistenceLDAP"));
        }

        try
        {
            PropertyUtils.copyProperties(jbTop, jbTopClone);
        }
        catch (Exception e)
        {
            _logger.error(e);
            throw new PersistenceException(
                "transferFromClone.copyProperties error " + e.getMessage());
        }
    }

    /**
     * Gets attribute value according to field definition in faare_mapping.xml.
     * Case of single valued attributes.
     *
     * @param ld LDAP connection.
     * @param attr LDAP attribute.
     * @param fieldType Field descriptor.
     * @param userContext Current user context.
     *
     * @return Attribute value(s)
     *
     * @throws PersistenceException in case of null argument
     */
    private static Object getValue(LDAPConnection ld, LDAPAttribute attr,
        JBFieldDescriptor fieldType, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------GETVALUE DEBUT--------------");

        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "getValue", "PersistenceLDAP"));
        }

        if (attr == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "attr", "getValue", "PersistenceLDAP"));
        }

        if (fieldType == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "fieldType", "getValue",
                    "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "getValue",
                    "PersistenceLDAP"));
        }

        if (fieldType.isByteType())
        {
            _logger.debug("GETVALUE fieldType.isByteType()");

            /*Objet de type bytes*/
            Enumeration enum1 = attr.getByteValues();

            return enum1.nextElement();
        }
        else if (fieldType.isIntegerType())
        { /*Objet de type Integer*/
            _logger.debug("GETVALUE fieldType.isIntegerType()");

            String[] values = attr.getStringValueArray();

            return new Integer(values[0]);
        }
        else if (fieldType.isJBTopType())
        {
            _logger.debug("GETVALUE fieldType.isJBTopType()");

            /*Objet de type objet m�tier*/
            String[] values = attr.getStringValueArray();
            JBTop jbTop = null;

            try
            {
                _logger.debug("GETVALUE values[0] : " + values[0]);

                JBTop jbTopCache = getFromCache(LdapUtil.formatDN(values[0]),
                        userContext.getCache());

                if (jbTopCache != null)
                {
                    _logger.debug("GETVALUE jbTop already in cache");
                    jbTop = jbTopCache;
                }
                else
                {
                    LDAPEntry entry = ld.read(values[0], _attrsSelected);
                    _logger.debug("GETVALUE entry : " + entry);

                    if (entry != null)
                    {
                        jbTop = internalSearch(ld, entry, null, userContext);
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }

            return jbTop;
        }
        else
        {
            /* String ou Autres types : renvoyer le premier element comme String*/
            String[] values = attr.getStringValueArray();

            return values[0];
        }
    }

    /**
     * Gets attribute value according to field definition in faare_mapping.xml.
     * Case of multi valued attributes.
     *
     * @param ld LDAP connection.
     * @param attr LDAP attribute.
     * @param fieldType Field descriptor.
     * @param userContext Current user context.
     *
     * @return Attribute value(s)
     *
     * @throws PersistenceException in case of null argument
     */
    private static Enumeration getValueCollection(LDAPConnection ld,
        LDAPAttribute attr, JBFieldDescriptor fieldType, UserContext userContext)
        throws PersistenceException
    {
        if (ld == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "ld", "getValueCollection",
                    "PersistenceLDAP"));
        }

        if (attr == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "attr", "getValueCollection",
                    "PersistenceLDAP"));
        }

        if (fieldType == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "fieldType", "getValueCollection",
                    "PersistenceLDAP"));
        }

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL", "userContext", "getValueCollection",
                    "PersistenceLDAP"));
        }

        if (fieldType.isByteType())
        { /*Attribut de type bytes*/
            _logger.debug("getValueCollection byte");
            return attr.getByteValues();
        }
        else if (fieldType.isJBTopType())
        {
            /*Attribut de type objet m�tier*/
            _logger.debug("getValueCollection fieldType de type JBTop ");

            List attrValues = new ArrayList();
            JBTop jbTop = null;
            String tmpDn = null;

            Enumeration enum1 = attr.getStringValues();

            while (enum1.hasMoreElements())
            {
                tmpDn = (String) enum1.nextElement();

                try
                {
                    LDAPEntry entry = ld.read(tmpDn, _attrsSelected);

                    if (entry != null)
                    {
                        jbTop = internalSearch(ld, entry, null, userContext);
                    }
                }
                catch (LDAPException le)
                {
                    _logger.error(MessageUtil.formatMessage("MSG_LDAP_ERROR",
                            LdapUtil.getLDAPErrorMessage(le)));
                }

                attrValues.add(jbTop);
            }

            return Collections.enumeration(attrValues);
        }
        else if (fieldType.isIntegerType())
        { /*Attribut de type Integer*/

            List attrValues = new ArrayList();
            Enumeration enum1 = attr.getStringValues();
            String tmpVal;

            while (enum1.hasMoreElements())
            {
                tmpVal = (String) enum1.nextElement();

                // on choisit de ne pas gerer numberFormatException. Par contre
                // l'appli doit prevoir de capturer  RuntimeException !
                attrValues.add(new Integer(tmpVal));
            }

            return Collections.enumeration(attrValues);
        }
        else
        {
            /* String ou Autres types */
            return attr.getStringValues();
        }
    }

    //getValueCollection

    /**
     * Adds an object to cache is cache maximum size is not reached.
     *
     * @param jbTop Object to be added.
     * @param hCache Cache.
     * @param userContext Current user context.
     *
     */
    private static void addToCache(JBTop jbTop, Map hCache,
        UserContext userContext) //throws PersistenceException
    {
        if ((jbTop != null) &&
                (hCache.size() < userContext.getLdapConfig().getObjectCacheSize()))
        {
            hCache.put(jbTop.getDn(), jbTop);
        }
    }

    //addToCache

    /**
     * Replaces an object in cache.
     * @param jbTop Object to be added.
     * @param hCache Cache.
     *
     */
    private static void replaceInCache(JBTop jbTop, Map hCache)
        //throws PersistenceException
    {
        _logger.debug("REPLACEINCACHE pour dn : " + jbTop.getDn());

        JBTop oldJBTop = null;

        if (jbTop != null)
        {
            oldJBTop = getFromCache(jbTop.getDn(), hCache);
            hCache.remove(jbTop.getDn());
            hCache.put(jbTop.getDn(), jbTop);
        }
    }

    //replaceInCache

    /**
     * Gets an object from cache.
     *
     * @param dn Searched entry dname.
     * @param hCache Cache.
     * @return Requested entry, null if not found.
     */
    private static JBTop getFromCache(String dn, Map hCache)
    {
        return (JBTop) hCache.get(LdapUtil.formatDN(dn));
    }

    /**
     * Sets a counter in a technical entry, with an atomic method.
     *
     * @param dn Technical entry dname.
     * @param attribute Counter attribute name
     * @param oldValue Counter old value.
     * @param newValue Counter new value.
     * @param userContext Current user context.
     *
     * @return true if success, false if atomic update failed.
     *
     * @throws PersistenceException in case of null argument or LDAP error.
     */
    public static boolean setCounter(String dn, String attribute,
        String oldValue, String newValue, UserContext userContext)
        throws PersistenceException
    {
        _logger.debug("-----------setCounter DEBUT ----------");

        if (userContext == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (attribute == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (oldValue == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        if (newValue == null)
        {
            throw new PersistenceException(MessageUtil.formatMessage(
                    "MSG_ARGUMENT_NULL"));
        }

        boolean success = true;

        try
        {
            LDAPConnection ld = userContext.getLd();

            LDAPModificationSet ldapModificationSet = new LDAPModificationSet();

            LDAPAttribute oldLdapAttr = new LDAPAttribute(attribute, oldValue);
            LDAPAttribute newLdapAttr = new LDAPAttribute(attribute, newValue);

            ldapModificationSet.add(LDAPModification.DELETE, oldLdapAttr);
            ldapModificationSet.add(LDAPModification.REPLACE, newLdapAttr);

            ld.modify(dn, ldapModificationSet);
        }
        catch (LDAPException le)
        {
            if (le.getLDAPResultCode() == LDAPException.NO_SUCH_ATTRIBUTE)
            {
                _logger.debug("-----------setCounter got so such attribute---");

                return false;
            }

            _logger.debug("-----------setCounter got " +
                le.getLDAPResultCode());
            throw new PersistenceException(LdapUtil.getLDAPErrorMessage(le), le);
        }

        _logger.debug("-----------setCounter FIN OK ----------");

        return success;
    }
}
